﻿using System.Collections.Generic;
using System.Threading;

namespace Phoenix.Xna.Framework.MessagePipeline
{
    public class MessageService : Service, IMessageService
    {
        private List<IMessageProcessor> _messageProcessors = new List<IMessageProcessor>();
        private Thread _messageDispatchThread;
        private Queue<IMessage> _messageQueue = new Queue<IMessage>();
        private bool _dispatchRunning;

        public MessageService()
            : base()
        {
            Initialize();
        }

        public MessageService(string id)
            : base(id)
        {
            Initialize();
        }

        private void Initialize()
        {
            if (Engine.Instance.Services != null)
            {
                Engine.Instance.Services.AddService<IMessageService>(this);
            }
        }

        private void DispatchMessages()
        {
            while (_dispatchRunning)
            {
                IMessage message = null;

                lock (_messageQueue)
                {
                    while (_messageQueue.Count == 0 && _dispatchRunning)
                    {
                        Monitor.Wait(_messageQueue);
                    }

                    if (_messageQueue.Count > 0)
                    {
                        message = _messageQueue.Dequeue();
                    }
                }

                foreach (IMessageProcessor processor in _messageProcessors)
                {
                    processor.ProcessMessage(message);
                }
            }
        }

        #region IMessageService Members

        public void Start()
        {
            _dispatchRunning = true;

            if (_messageDispatchThread == null || !_messageDispatchThread.IsAlive)
            {
                _messageDispatchThread = new Thread(DispatchMessages);
                _messageDispatchThread.Name = "Dispatch Messages Thread";
                _messageDispatchThread.IsBackground = true;
                _messageDispatchThread.Start();
            }
        }

        public void Register(IMessageProcessor processor)
        {
            _messageProcessors.Add(processor);
        }

        public void Unregister(IMessageProcessor processor)
        {
            _messageProcessors.Remove(processor);
        }

        public void SendMessage(IMessage message)
        {
            if (message != null)
            {
                lock (_messageQueue)
                {
                    _messageQueue.Enqueue(message);
                    Monitor.PulseAll(_messageQueue);
                }
            }
        }

        #endregion
    }
}
